package com.ssy.jt808.gateway.domain.service;

import com.ssy.jt808.gateway.domain.exception.TerminalUnauthorizedException;
import com.ssy.jt808.gateway.domain.pojo.TerminalInfo;
import com.ssy.jt808.gateway.infrastructure.constant.TerminalMessageCache;
import com.ssy.jt808.gateway.infrastructure.gateway.TerminalInfoCacheRepository;
import com.ssy.jt808.gateway.infrastructure.gateway.VehicleInfoApi;
import com.ssy.jt808.gateway.infrastructure.gateway.pojo.TerminalBindInfoDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service;

import java.util.Objects;

/**
 * @author zeno
 */
@Service
public class TerminalService{

  private       VehicleInfoApi              vehicleInfoApi;
  private final Cache                       terminalTokenCache;
  private       TerminalInfoCacheRepository terminalInfoCacheRepository;

  public TerminalService( CacheManager cacheManager ){
    terminalTokenCache = cacheManager.getCache(TerminalMessageCache.TERMINAL_TOKEN.cacheName());
  }

  /**
   * 上线处理
   *
   * @return 通讯 token
   */
  public String onOnline( TerminalInfo terminalInfo ){

    String phoneNo = terminalInfo.getPhoneNo();
    TerminalInfo cachedTerminalInfo = terminalInfoCacheRepository.getTerminalInfo(phoneNo);
    if( cachedTerminalInfo == null ){
      TerminalBindInfoDTO bindInfo = vehicleInfoApi.getBindInfoByPhoneNo(phoneNo);
      terminalInfo.setTerminalId(bindInfo.getTerminalId());
      terminalInfo.setPlateNo(bindInfo.getPlateNo());
      terminalInfo.setVehicleId(bindInfo.getVehicleId());
      terminalInfo.setVehicleOrgId(bindInfo.getVehicleOrgId());
      terminalInfo.setOrgAncestors(bindInfo.getOrgAncestors());
      terminalInfo.setDriverId(bindInfo.getDriverId());

      terminalInfoCacheRepository.setTerminalInfo(phoneNo, terminalInfo);
    }
    else{
      terminalInfo.setTerminalId(cachedTerminalInfo.getTerminalId());
      terminalInfo.setVehicleId(cachedTerminalInfo.getVehicleId());
      terminalInfo.setPlateNo(cachedTerminalInfo.getPlateNo());
      terminalInfo.setVehicleOrgId(cachedTerminalInfo.getVehicleOrgId());
      terminalInfo.setOrgAncestors(cachedTerminalInfo.getOrgAncestors());
      terminalInfo.setDriverId(cachedTerminalInfo.getDriverId());
    }

    // 通过车辆管理服务地址获取相对应的本地地址。
    String token = generateToken(terminalInfo);
    terminalTokenCache.put(terminalInfo.getPhoneNo(), token);
    return token;
  }

  public TerminalInfo doVerifyToken( String terminalPhoneNo, String verifyToken ){
    TerminalInfo terminalInfo = new TerminalInfo();
    terminalInfo.setPhoneNo(terminalPhoneNo);

    String token = terminalTokenCache.get(terminalPhoneNo, String.class);
    if( !Objects.equals(token, verifyToken) ){
      throw new TerminalUnauthorizedException("终端({0})重连，token 认证失败({1})",
                                              terminalPhoneNo,
                                              verifyToken);
    }

    TerminalBindInfoDTO bindInfoDTO = vehicleInfoApi.getBindInfoByPhoneNo(terminalPhoneNo);

    terminalInfo.setTerminalId(bindInfoDTO.getTerminalId());
    terminalInfo.setVehicleId(bindInfoDTO.getVehicleId());
    terminalInfo.setPlateNo(bindInfoDTO.getPlateNo());
    terminalInfo.setDriverId(bindInfoDTO.getDriverId());
    terminalInfo.setOrgAncestors(bindInfoDTO.getOrgAncestors());
    terminalInfo.setVehicleOrgId(bindInfoDTO.getVehicleOrgId());

    terminalInfoCacheRepository.setTerminalInfo(terminalPhoneNo, terminalInfo);
    return terminalInfo;
  }

  public TerminalInfo getTerminalInfo( String terminalPhoneNo ){
    return terminalInfoCacheRepository.getTerminalInfo(terminalPhoneNo);
  }

  @Autowired
  public void setTerminalInfoRepository( TerminalInfoCacheRepository terminalInfoCacheRepository ){
    this.terminalInfoCacheRepository = terminalInfoCacheRepository;
  }

  @Autowired
  public void setVehicleInfoApi( VehicleInfoApi vehicleInfoApi ){
    this.vehicleInfoApi = vehicleInfoApi;
  }

  private String generateToken( TerminalInfo terminalInfo ){
    return terminalInfo.getTerminalId() + ":" + terminalInfo.getPhoneNo();
  }
}
